#include "StdAfx.h"
#include "SocketOptionBase.h"

using namespace Adaptive::Win32;
using namespace Adaptive::Network;
using namespace Adaptive::Network::Sockets;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
generic<typename T>
SocketOptionBase<T>::SocketOptionBase(SocketOptionLevel level, SocketOptionName name)
{
	_optionLevel = level;
	_optionName = name;
	_value = T();
}
// Initializes a new instance of the class.
generic<typename T>
SocketOptionBase<T>::SocketOptionBase(SocketOptionLevel level, SocketOptionName name, T value)
{
	_optionLevel = level;
	_optionName = name;
	_value = value;
}
generic<typename T>
SocketOptionLevel SocketOptionBase<T>::Level::get()
{
	return _optionLevel;
}
generic<typename T>
void SocketOptionBase<T>::Level::set(SocketOptionLevel value)
{
	_optionLevel = value;
}
generic<typename T>
SocketOptionName SocketOptionBase<T>::Name::get()
{
	return _optionName;
}
generic<typename T>
void SocketOptionBase<T>::Name::set(SocketOptionName value)
{
	if (IsNameOptionValidForLevel(_optionLevel, value))
		_optionName = value;
	else
		throw gcnew SocketOptionException(_optionLevel, value);
}
generic<typename T>
T SocketOptionBase<T>::Value::get()
{
	return _value;
}
generic<typename T>
void SocketOptionBase<T>::Value::set(T value)
{
	_value = value;
}
generic<typename T>
bool SocketOptionBase<T>::IsNameOptionValidForLevel(SocketOptionLevel level, SocketOptionName name)
{
	bool returnValue = false;

	switch(level)
	{
	case SocketOptionLevel::Socket:
		returnValue =  ((name == SocketOptionName::Broadcast) || 
			(name == SocketOptionName::DontLinger) || 
			(name == SocketOptionName::Debug) || 
			(name == SocketOptionName::Error) || 
			(name == SocketOptionName::OutOfBandInline) || 
			(name == SocketOptionName::ReceiveBuffer) || 
			(name == SocketOptionName::ReceiveTimeout) || 
			(name == SocketOptionName::ReuseAddress) || 
			(name == SocketOptionName::SendBuffer) || 
			(name == SocketOptionName::SendTimeout) || 
			(name == SocketOptionName::Type));
		break;

	case SocketOptionLevel::IP:
		returnValue = ((name == SocketOptionName::HeaderIncluded) ||
					   (name == SocketOptionName::IPOptions) || 
					   (name == SocketOptionName::IpTimeToLive) || 
					   (name == SocketOptionName::MulticastInterface) || 
					   (name == SocketOptionName::MulticastLoopback) || 
					   (name == SocketOptionName::MulticastTimeToLive) || 
					   (name == SocketOptionName::TypeOfService) || 
					   (name == SocketOptionName::UseLoopback));
		break;
	case SocketOptionLevel::Tcp:
		returnValue = ((name == SocketOptionName::BsdUrgent) ||
					   (name == SocketOptionName::Expedited) || 
					   (name == SocketOptionName::NoDelay));

		break;
	case SocketOptionLevel::Udp:
		returnValue = ((name == SocketOptionName::ChecksumCoverage) ||
						(name == SocketOptionName::NoChecksum));

		break;
	case SocketOptionLevel::IPv6:
		returnValue =(name == SocketOptionName::HopLimit);

		break;
	}
	return returnValue;
}
#pragma endregion